/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.artic.jme3gui.client.loader;

import com.artic.jme3gui.client.ApplicationClient;
import com.artic.jme3gui.client.ApplicationConstants;
import com.artic.jme3gui.client.ApplicationSingelton;
import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Node;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author PaulSyntax
 */
public class LoadingState extends AbstractAppState {

    protected Node rootNode = new Node(ApplicationConstants.ROOT_NODE);
    protected Node guiNode = new Node(ApplicationConstants.GUI_NODE);

    private ApplicationClient game = null;
    protected BitmapFont loadingFont;
    protected BitmapText loadingText;
    private List<Future<AssetItem>> assetFutures;

    public LoadingState(ApplicationClient game) {
        this(game, 100, true);
    }

    public LoadingState(ApplicationClient game, int steps, boolean removeOnComplete) {
        this.game = game;
    }


    private class AppActionListener implements ActionListener {

        @Override
        public void onAction(String name, boolean value, float tpf) {
            if (!value) {
                return;
            }
            // Load other state
            game.loadGame();
        }
    }


    @Override
    public void initialize(AppStateManager stateManager, Application app) {
        try {
            super.initialize(stateManager, app);
            List<LoadItemCallable> tasks = new ArrayList<LoadItemCallable>();

            AssetItem assetItem = new AssetItem();
            assetItem.setFilename("Scenes/Example/Main.scene");
            assetItem.setType(AssetType.MODEL);
            LoadItemCallable itemload = new LoadItemCallable(assetItem, game.getAssetManager());
            tasks.add(itemload);
            assetItem = new AssetItem();
            assetItem.setFilename("Scenes/Example/Ninja.scene");
            assetItem.setType(AssetType.MODEL);
            itemload = new LoadItemCallable(assetItem, game.getAssetManager());
            tasks.add(itemload);

            ExecutorService executor = Executors.newCachedThreadPool();
            assetFutures =  executor.invokeAll(tasks); // fails in Java 5, but not in 6
            
        } catch (InterruptedException ex) {
            Logger.getLogger(LoadingState.class.getName()).log(Level.SEVERE, null, ex);
        }

        // Init input
        if (game.getInputManager() != null){
            game.getInputManager().addMapping(ApplicationConstants.MENU_EXIT, new KeyTrigger(KeyInput.KEY_ESCAPE));
        }
    }

    @Override
    public void stateAttached(AppStateManager stateManager) {
        game.getViewPort().attachScene(rootNode);
        game.getGUIViewPort().attachScene(guiNode);
    }

    @Override
    public void stateDetached(AppStateManager stateManager) {
        game.getViewPort().detachScene(rootNode);
        game.getGUIViewPort().detachScene(guiNode);
    }

    @Override
    public void render(RenderManager rm) {
    }

    @Override
    public void update(float tpf) {
        super.update(tpf);
        for (Future future: assetFutures){
            if (future.isDone()){
                try {
                   AssetItem assetItem = (AssetItem) future.get();
                   System.out.println("loading done for:"+assetItem.getFilename());
                   assetFutures.remove(future);
                   ApplicationSingelton.getInstance(game).getAssetItems().add(assetItem);
                   if (assetFutures.isEmpty()){
                         game.getInputManager().addListener(new AppActionListener(), ApplicationConstants.MENU_EXIT);
                   }
                   break;
                } catch (InterruptedException ex) {
                    Logger.getLogger(LoadingState.class.getName()).log(Level.SEVERE, null, ex);
                } catch (ExecutionException ex) {
                    Logger.getLogger(LoadingState.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

        rootNode.updateLogicalState(tpf);
        guiNode.updateLogicalState(tpf);
        rootNode.updateGeometricState();
        guiNode.updateGeometricState();
    }
}
